#include <iostream>
using namespace std;
#include <cstring>
#include <queue>
#include <unordered_map>
#include <vector>

/************************** DFS ***************************/

// 1~n 全排列：https://www.acwing.com/problem/content/844/
// 每次选个数字放到当前位置，再到下一个位置选个数字... (需要知道哪些数字能选)
/*
const int N = 10;
bool view[N];
int ret[N];
int n;
void dfs(int i)
{
    if (i == n)
    {
        for (int j = 0; j < n; ++j)
            printf("%d ", ret[j]);
        puts("");
    }
    for (int j = 1; j <= n; ++j)
    {
        if (!view[j])
        {
            ret[i] = j;
            view[j] = true;
            dfs(i + 1);
            view[j] = false;
        }
    }
}
int main()
{
    scanf("%d", &n);
    dfs(0);
    return 0;
}*/

// n皇后： https://www.acwing.com/problem/content/845/
/*
// 法一：每次在当前行选择一个位置放皇后，再去下一行选 (对角线、列不能相同)
const int N = 10;
int path[N]; //path[i] 表示第i行第path[i]列放了皇后
int n;
//列、正对角线、反对角线
bool col[N], dg[2 * N], udg[2 * N];

void dfs(int i)
{
    if (i == n)
    {
        for (int i = 0; i < n; ++i)
        {
            for (int j = 0; j < n; ++j)
            {
                if (path[i] == j)
                    printf("Q");
                else
                    printf(".");
            }
            puts("");
        }
        puts("");
        return;
    }
    for (int j = 0; j < n; ++j)
    {
        //根据数学直线方程 (画图)
        if (!col[j] && !dg[i + j] && !udg[j - i + n])
        {
            path[i] = j;
            col[j] = dg[i + j] = udg[j - i + n] = true;
            dfs(i + 1);
            col[j] = dg[i + j] = udg[j - i + n] = false;
        }
    }
}
int main()
{
    scanf("%d", &n);
    dfs(0);
    return 0;
}

//法二：更原始的搜索方式。每个点只考虑选或不选
const int N = 14;
int n;
//行、列、对角线、斜对角线
bool row[N], col[N], dg[2 * N], udg[2 * N];
char g[N][N];

void dfs(int x, int y, int cnt){
    if(x == n)
    {
        if(cnt == n)
        {
            for(int i = 0; i < n; ++i)
                puts(g[i]);
            puts("");
        }
        return;
    }
    int i = x, j = y;
    if(++j == n)
    {
        j = 0;
        ++i;
    }
    //不选
    dfs(i, j, cnt);
    //选
    if(!row[x] && !col[y] && !dg[x + y] && !udg[y - x + n])
    {
        g[x][y] = 'Q';
        row[x] = col[y] = dg[x + y] = udg[y - x + n] = true;
        dfs(i, j, cnt + 1);
        row[x] = col[y] = dg[x + y] = udg[y - x + n] = false;
        g[x][y] = '.';
    }
}
int main()
{
    scanf("%d", &n);
    for(int i = 0; i < n; ++i)
    {
        for(int j = 0; j < n; ++j)
            g[i][j] = '.';
    }
    dfs(0, 0, 0);
    return 0;
}*/

/************************* BFS ***********************/
/*
//走迷宫：https://www.acwing.com/problem/content/846/
//0表示空地，1表示障碍

//第一种bfs。一层一层扩展
const int N = 110;
int g[N][N];        //地图
bool view[N][N];    //节点是否已访问
pair<int, int> pre[N][N]; //为了求最短路径，存放每个坐标的前驱
int n, m;
void bfs()
{
    int dx[4] = {1, 0, 0, -1};
    int dy[4] = {0, 1, -1, 0};
    queue<pair<int, int>> q;
    q.push({1, 1});
    int len = 0;
    while (q.size())
    {
        ++len;
        int sz = q.size(); //sz就是当前层的总结点数
        while (sz--)
        {
            auto [x, y] = q.front();
            q.pop();
            for (int i = 0; i < 4; ++i)
            {
                int a = x + dx[i], b = y + dy[i];
                if (a >= 1 && a <= n && b >= 1 && b <= m && !view[a][b] && g[a][b] == 0)
                {
                    q.push({a, b});
                    pre[a][b] = { x,y };
                    view[a][b] = true;
                }
            }
        }
    }
    // 由于最后一层也会往后搜索一层，所以要-1
    printf("最短距离：%d\n", len - 1);
    // 打印路径
    int x = n, y = m;
    while (!(x == 1 && y == 1))
    {
        printf("%d %d\n", x, y);
        auto [a, b] = pre[x][y];
        x = a, y = b;
    }
}

// //第二种bfs。一个点一个点扩展
// const int N = 110;
// int g[N][N];    //地图
// int d[N][N];    //d[i][j]: 从(0,0)到达(i,j)的距离
// pair<int, int> pre[N][N], q[N * N]; //q是手撕队列
// int n, m;
// void bfs()
// {
//     memset(d, -1, sizeof d);
//     int dx[4] = {1, 0, 0, -1};
//     int dy[4] = {0, 1, -1, 0};
//     int h = 0, t = 0; //h队头，t队尾
//     q[t++] = {1, 1};
//     d[1][1] = 0;
//     while (h != t)
//     {
//         auto [x, y] = q[h++];
//         for (int i = 0; i < 4; ++i)
//         {
//             int a = x + dx[i], b = y + dy[i];
//             if (a >= 1 && a <= n && b >= 1 && b <= m && d[a][b] == -1 && g[a][b] == 0)
//             {
//                 q[t++] = {a, b};
//                 d[a][b] = d[x][y] + 1;
//                 pre[a][b] = {x, y};
//             }
//         }
//     }
//     printf("最短距离：%d\n", d[n][m]);
//     int x = n, y = m;
//     while(!(x == 1 && y == 1))
//     {
//         printf("%d %d\n", x, y);
//         auto[a, b] = pre[x][y];
//         x = a, y = b;
//     }
// }

int main()
{
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            scanf("%d", &g[i][j]);
    bfs();
    return 0;
}*/

/****************** 树和图的存储及遍历 ******************/
// //邻接矩阵
// const int N = 1e5 + 10;
// int g[N][N];
// void add(int a, int b, int c)
// {
//     g[a][b] = c;
// }

/*
// //邻接表 （类似哈希的拉链法）
const int N = 1e5 + 10;
int h[N], e[N], ne[N], w[N], idx;
//h[1]  表示 将 第1个点的所有邻接点建立成单链表后的头节点位置
//e[i]  表示i位置存放的节点是e[i]
//ne[i] i位置的下一个位置
//w[i]  权值
//idx   用到第几个节点了
void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

bool view[N];
void dfs(int i)
{
    view[i] = true;
    printf("%d ", i);
    for (int j = h[i]; j != -1; j = ne[j])
    {
        int u = e[j];
        if (!view[u])
            dfs(u);
    }
}

void bfs(int i)
{
    queue<int> q;
    q.push(i);
    view[i] = true;
    while (q.size())
    {
        int u = q.front();
        printf("%d ", u);
        q.pop();
        for (int j = h[u]; j != -1; j = ne[j])
        {
            if (!view[e[j]])
            {
                q.push(e[j]);
                view[e[j]] = true;
            }
        }
    }
}

int main()
{
    int n;
    memset(h, -1, sizeof h);
    scanf("%d", &n);
    int a, b;
    while (n--)
    {
        scanf("%d %d", &a, &b);
        add(a, b);
    }
    dfs(1);
    // puts("");
    //bfs(1);
    return 0;
}*/

/***** 847.图中点的层次 https://www.acwing.com/activity/content/problem/content/910/ *****/
// 求出 1 号点到 n 号点的最短距离
// 最短路，直接用bfs
/*
const int N = 1e5 + 10;
int h[N], e[N], ne[N], idx, q[N];
bool view[N];
int n, m; // n个节点，m条边

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

int bfs()
{
    int hh = 0, tt = 0, len = 0;
    q[tt++] = 1;
    view[1] = true;
    while (hh != tt)
    {
        int sz = tt - hh; //把当前层的节点全弹出后，队列里的所有元素就是下一层的
        while (sz--)
        {
            int u = q[hh++];
            if (u == n)
                return len;
            for (int i = h[u]; i != -1; i = ne[i])
            {
                if (!view[e[i]])
                {
                    view[e[i]] = true;
                    q[tt++] = e[i];
                }
            }
        }
        len++;
    }
    return -1;
}
int main()
{
    memset(h, -1, sizeof h);
    scanf("%d %d", &n, &m);
    int a, b;
    while (m--)
    {
        scanf("%d %d", &a, &b);
        add(a, b);
    }
    printf("%d", bfs());
    return 0;
}*/

/* 848. 有向图的拓扑序列。https://www.acwing.com/activity/content/problem/content/911/ */
// 每次把所有入度为0的点放入队列，并删除其邻接边，更新入度
/*
const int N = 1e5 + 10;
int h[N], e[N], ne[N], idx, q[N];
int d[N]; // 每个点的入度
int n, m;
void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

bool topsort()
{
    int hh = 0, tt = 0;
    // 入度为0的入队
    for (int i = 1; i <= n; ++i)
        if (d[i] == 0)
            q[tt++] = i;

    while (hh != tt)
    {
        int f = q[hh++];
        // 删除邻接边，更新入度
        for (int i = h[f]; i != -1; i = ne[i])
        {
            int u = e[i];
            if (--d[u] == 0)
                q[tt++] = u;
        }
    }
    // 如果没遍历完，说明有环
    if (tt != n)
        puts("-1");
    else
    {
        for (int i = 0; i < tt; ++i)
            printf("%d ", q[i]);
    }
}
int main()
{
    memset(h, -1, sizeof h);
    scanf("%d %d", &n, &m);
    int a, b;
    while (m--)
    {
        scanf("%d %d", &a, &b);
        add(a, b);
        d[b]++;
    }
    topsort();
    return 0;
}*/

/*补：unordered_map<pair<int,int>, int> 用法
pair<T1, T2>没有哈希函数，需要自己写
struct hash_pair
{
    // 一般直接采用移位加异或得到哈希值
    template<class T1, class T2>
    size_t operator()(const pair<T1, T2>& p) const{
        return hash<T1>()(p.first) ^ (hash<T2>()(p.second) << 1);
    }
}
struct equal_pair
{
    template<class T1, class T2>
    bool operator()(const pair<T1, T2>& p1, const pair<T1, T2>& p2)
    {
        return p1.first == p2.first && p1.second == p2.second;
    }
}
unordered_map<pair<int,int>, int, hash_pair, equal_pair> ha;
*/

/*作业
846树的重心 https://www.acwing.com/problem/content/848/

*/
const int N = 100010;
int n, ans;
int h[N], e[N], ne[N], idx;
bool view[N];

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
// 返回以i为根的子树的总结点
int dfs(int i)
{
    view[i] = true;
    int sum = 1, res = 0; // sum记录总结点
    for (int j = h[i]; j != -1; j = ne[j])
    {
        int u = e[j];
        if (!view[u])
        {
            int tmp = dfs(u);    // 子树的节点
            res = max(tmp, res); // res求所有子树中总节点最大那个
            sum += tmp;
        }
    }
    // 不会回退，i上面可能还有节点
    res = max(res, n - sum);
    ans = min(ans, res);
    return sum;
}

int main()
{
    scanf("%d", &n);
    ans = n;
    int a, b;
    for (int i = 0; i < n - 1; ++i)
    {
        scanf("%d %d", &a, &b);
        add(a, b);
        add(b, a);
    }
    dfs(1);
    printf("%d", ans);
    return 0;
}